package com.wuliu.common.utils;

import com.alibaba.fastjson.JSONObject;
import com.wuliu.common.exception.ServiceException;
import com.wuliu.common.utils.http.HttpUtils;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;

/**
 * 腾讯地理位置服务
 */
public class TencentLocationUtil {
    private static final String TENCENT_API_KEY = DictUtils.getDictValue("tencent_map_params","api_key");

    //本接口提供由经纬度到文字地址及相关位置信息的转换能力
    private static final String TENCENT_API_GEOCODER = "https://apis.map.qq.com/ws/geocoder/v1/?location=";
    //本接口提供由文字地址到经纬度的转换能力
    private static final String TENCENT_API_GEOCODER_REV = "https://apis.map.qq.com/ws/geocoder/v1/?address=";
    //距离批量计算
    private static final String TENCENT_API_DISTANCE = "https://apis.map.qq.com/ws/distance/v1/matrix?";
    //获取输入关键字的补完与提示，帮助用户快速输入
    private static final String TENCENT_API_SUGGESTION = "https://apis.map.qq.com/ws/place/v1/suggestion/?";

    /**
     * 将经纬度，解析为地址
     *
     * @param lng 经度
     * @param lat 纬度
     * @return
     */
    public static String geoCoder(String lng, String lat) {
        try {
            String location = lat + "," + lng;
            String apiUrl = TENCENT_API_GEOCODER + location + "&key=" + TENCENT_API_KEY;
            Map resMap = parseTencentApiResult(HttpUtils.sendGet(apiUrl, null));

            JSONObject obj = (JSONObject) resMap.get("result");
            return obj.getString("address");
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 将地址，解析为经纬度
     *
     * @param address 地址（注：地址中请包含城市名称，否则会影响解析效果）
     * @return Map
     */
    public static Map<String,String> geoCoderRev(String address) {
        try {
            String apiUrl = TENCENT_API_GEOCODER_REV + address + "&key=" + TENCENT_API_KEY;
            Map resMap = parseTencentApiResult(HttpUtils.sendGet(apiUrl, null));

            JSONObject obj = (JSONObject) resMap.get("result");
            JSONObject location = (JSONObject) obj.get("location");

            Map<String,String> map = new HashMap();
            map.put("lng", location.getString("lng"));
            map.put("lat", location.getString("lat"));

            return map;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 1对多距离批量计算【距离矩阵（DistanceMatrix），用于批量计算一组起终点的路面距离（或称导航距离）】
     *
     * @param sourceLoc  lat,lng
     * @param dstTreeMap 目的地经纬度map,key由业务自定义 , value格式为：lat,lng
     * @return sortedMap key由业务自定义, value为距离【单位：K米】
     */
    public static Map getDistance(String sourceLoc, TreeMap<String, Object> dstTreeMap) {
        try {
            StringBuilder str = new StringBuilder();
            Set<Map.Entry<String, Object>> entries = dstTreeMap.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                if (str.length() == 0) {
                    str.append(entry.getValue());
                } else {
                    str.append(";").append(entry.getValue());
                }
            }

            String apiUrl = TENCENT_API_DISTANCE + "mode=driving" + "&from=" + sourceLoc + "&to=" + str.toString()
                    + "&key=" + TENCENT_API_KEY;
            Map resMap = parseTencentApiResult(HttpUtils.sendGet(apiUrl, null));

            JSONObject obj = (JSONObject) resMap.get("result");
            List<JSONObject> rows = (List<JSONObject>) obj.get("rows");
            if (CollectionUtils.isEmpty(rows)) throw new ServiceException("获取距离异常");
            List<JSONObject> elements = (List<JSONObject>) rows.get(0).get("elements");
            int i = 0;
            for (JSONObject jsonObj : elements) {
                i++;
                BigDecimal distanct = jsonObj.getBigDecimal("distance");
                BigDecimal duration = jsonObj.getBigDecimal("duration");
                distanceMatch(dstTreeMap, distanct, i);
            }

            return dstTreeMap;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取输入关键字的补完与提示，帮助用户快速输入
     *
     * @param keyword 经度
     * @param region  纬度
     * @return
     */
    public static List<JSONObject> suggestion(String keyword, String region) {
        try {
            String apiUrl = TENCENT_API_SUGGESTION + "region=" + region + "&keyword=" + keyword + "&key=" + TENCENT_API_KEY + "";
            String resStr = HttpUtils.sendGet(apiUrl, null);


            JSONObject resMap = JSONObject.parseObject(resStr);
            short status = resMap.getShort("status");
            if (0 != status) {
                throw new ServiceException((String) resMap.getString("message"));
            } else {
                return (List<JSONObject>) resMap.get("data");
            }
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }
    }


    private static void distanceMatch(TreeMap<String, Object> map, BigDecimal distance, int i) {
        Set<Map.Entry<String, Object>> entries = map.entrySet();
        int j = 0;
        for (Map.Entry<String, Object> entry : entries) {
            j++;
            if (j == i) {
                entry.setValue(distance.divide(new BigDecimal(1000), 2, BigDecimal.ROUND_HALF_UP).toString());
                break;
            }
        }
    }

    //根据value排序 - 升序
    public static List sortByValue(TreeMap map) {
        List<Map.Entry<String, Object>> list = new ArrayList<Map.Entry<String, Object>>(map.entrySet());

        Collections.sort(list, new Comparator<Map.Entry<String, Object>>() {
            //升序排序
            public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
                return new BigDecimal((String) o1.getValue()).compareTo(new BigDecimal((String) o2.getValue()));
//                 ((new BigDecimal(o1.getValue())).compareTo((BigDecimal) o2.getValue());
            }
        });

        for (Map.Entry<String, Object> e : list) {
            System.out.println(e.getKey() + ":" + e.getValue());
        }

        return list;
    }

    private static Map parseTencentApiResult(String result) {
        JSONObject obj = JSONObject.parseObject(result);
        Short status = obj.getShort("status");
        if (0 != status) throw new ServiceException(obj.getString("message"));

        Map map = new HashMap();
        map.put("result", obj.getJSONObject("result"));

        return map;
    }

    /**
     * 腾讯API地址调用
     *
     * @param paramMap
     * @return name1=value1&name2=value2
     */
    private static Map getTencentApiCall(Map<String, String> paramMap) {
        StringBuilder str = new StringBuilder();
        for (String key : paramMap.keySet()) {
            String value = paramMap.get(key).toString();
            if (str.length() == 0) {
                str.append(key + "=" + value);
            } else {
                str.append("&" + key + "=" + value);
            }
        }
        String res = HttpUtils.sendGet(TENCENT_API_GEOCODER, str.toString());
        System.out.println("腾讯地理位置服务结果:" + res);

        return null;
    }
}
